﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace SafeLoad.NControl
{
    /// <summary>
    /// NMultiPipe.xaml 的交互逻辑
    /// </summary>
    public partial class NMultiPipe : UserControl
    {
        public NMultiPipe()
        {
            InitializeComponent();
        }

        public static readonly DependencyProperty LinePointsProperty =
          DependencyProperty.Register("LinePoints", typeof(string),
            typeof(NMultiPipe), new PropertyMetadata("",
              new PropertyChangedCallback(RenderUpdateByPropertyChanged)));
        public string LinePoints
        {
            get { return (string)GetValue(LinePointsProperty); }
            set { SetValue(LinePointsProperty, value); }
        }

        public static readonly DependencyProperty LineWidthProperty =
          DependencyProperty.Register("LineWidth", typeof(double),
            typeof(NMultiPipe), new PropertyMetadata(10d,
              new PropertyChangedCallback(RenderUpdateByPropertyChanged)));
        public double LineWidth
        {
            get { return (double)GetValue(LineWidthProperty); }
            set { SetValue(LineWidthProperty, value); }
        }

        public Color EdgeColor
        {
            get { return (Color)GetValue(EdgeColorProperty); }
            set { SetValue(EdgeColorProperty, value); }
        }
        public static readonly DependencyProperty EdgeColorProperty =
            DependencyProperty.Register("EdgeColor", typeof(Color), typeof(NMultiPipe), 
                new PropertyMetadata(Colors.LightGray, new PropertyChangedCallback(RenderUpdateByPropertyChanged)));

        public Color CenterColor
        {
            get { return (Color)GetValue(CenterColorProperty); }
            set { SetValue(CenterColorProperty, value); }
        }
        public static readonly DependencyProperty CenterColorProperty =
            DependencyProperty.Register("CenterColor", typeof(Color), typeof(NMultiPipe), 
                new PropertyMetadata(Colors.LightGray, new PropertyChangedCallback(RenderUpdateByPropertyChanged)));


        public static void RenderUpdateByPropertyChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs e)
        {
            if (dependency is NMultiPipe curve)
            {
                curve.UpdateCanvas();
            }
        }

        private void UpdateCanvas()
        {
            LinearGradientBrush horizontalBrush = new LinearGradientBrush();
            horizontalBrush.StartPoint = new Point(0, 0);
            horizontalBrush.EndPoint = new Point(0, 1);
            horizontalBrush.GradientStops.Add(new GradientStop(EdgeColor, 0));
            horizontalBrush.GradientStops.Add(new GradientStop(CenterColor, 0.5));
            horizontalBrush.GradientStops.Add(new GradientStop(EdgeColor, 1));

            LinearGradientBrush verticalBrush = new LinearGradientBrush();
            verticalBrush.StartPoint = new Point(0, 0);
            verticalBrush.EndPoint = new Point(1, 0);
            verticalBrush.GradientStops.Add(new GradientStop(EdgeColor, 0));
            verticalBrush.GradientStops.Add(new GradientStop(CenterColor, 0.5));
            verticalBrush.GradientStops.Add(new GradientStop(EdgeColor, 1));

            double halfWidth = LineWidth / 2;
            mainCanvas.Children.Clear();
            List<Point> pointList = GetPointList();
            for (int i = 1; i < pointList.Count; i++)
            {
                Point p1 = pointList[i - 1];
                Point p2 = pointList[i];

                double bgOffset = i > 1 ? halfWidth : 0;
                double edOffset = (i == pointList.Count - 1) ? 0 : halfWidth;

                if (Math.Abs(p1.X - p2.X) < 0.01)
                {
                    Rectangle rectangle = new Rectangle();
                    rectangle.Width = LineWidth;
                    rectangle.Height = Math.Abs(p1.Y - p2.Y) - (bgOffset + edOffset);
                    rectangle.Fill = verticalBrush;
                    mainCanvas.Children.Add(rectangle);
                    Canvas.SetLeft(rectangle, p1.X - halfWidth);
                    if (p2.Y > p1.Y)
                    {
                        Canvas.SetTop(rectangle, Math.Min(p1.Y, p2.Y) + bgOffset);
                    }
                    else
                    {
                        Canvas.SetTop(rectangle, Math.Min(p1.Y, p2.Y) + edOffset);
                    }
                }
                else
                {
                    //水平
                    Rectangle rectangle = new Rectangle();
                    rectangle.Width = Math.Abs(p1.X - p2.X) - (bgOffset + edOffset);
                    rectangle.Height = LineWidth;
                    rectangle.Fill = horizontalBrush;
                    mainCanvas.Children.Add(rectangle);
                    if (p2.X > p1.X)
                    {
                        Canvas.SetLeft(rectangle, Math.Min(p1.X, p2.X) + bgOffset);
                    }
                    else
                    {
                        Canvas.SetLeft(rectangle, Math.Min(p1.X, p2.X) + edOffset);
                    }
                    Canvas.SetTop(rectangle, p1.Y - LineWidth / 2);
                }

                if (i >= 2)
                {
                    //判断是否需要画弯
                    Point p0 = pointList[i - 2];
                    //中心点时p1
                    //弯点
                    if (Math.Abs(p2.Y - p1.Y) < 1)
                    {
                        p0 = pointList[i];
                        p2 = pointList[i - 2];
                    }
                    //转换成 横，竖 形式
                    //double coefX = p0.X < p1.X ? -1 : 1;
                    //double coefY = p1.Y < p2.Y ? 1 : -1;
                    //double angleX = p1.X + halfWidth * coefX;
                    //double angleY = p1.Y + halfWidth * coefY;

                    Path path = new Path();
                    string pathStr = "";
                    RadialGradientBrush rgBrush = new RadialGradientBrush();
                    if (p0.X < p1.X)
                    {
                        if (p1.Y < p2.Y)
                        {
                            // 右下
                            pathStr = $"M 0,0 A {LineWidth},{LineWidth} 0 0 1 {LineWidth},{LineWidth} L 0,{LineWidth} Z";
                            rgBrush.GradientOrigin = new Point(0, 1);
                            rgBrush.Center = new Point(0, 1);
                        }
                        else
                        {
                            //右上
                            pathStr = $"M {LineWidth},0 A {LineWidth},{LineWidth} 0 0 1 0,{LineWidth} L 0,0 Z";
                            rgBrush.GradientOrigin = new Point(0, 0);
                            rgBrush.Center = new Point(0, 0);
                        }
                    }
                    else
                    {
                        if (p1.Y < p2.Y)
                        {
                            // 左下
                            pathStr = $"M {LineWidth},0 A {LineWidth},{LineWidth} 0 0 0 0,{LineWidth} L {LineWidth},{LineWidth} Z";
                            rgBrush.GradientOrigin = new Point(1, 1);
                            rgBrush.Center = new Point(1, 1);
                        }
                        else
                        {
                            //左上
                            pathStr = $"M 0,0 A {LineWidth},{LineWidth} 0 0 0 {LineWidth},{LineWidth} L {LineWidth},0 Z";
                            rgBrush.GradientOrigin = new Point(1, 0);
                            rgBrush.Center = new Point(1, 0);
                        }
                    }

                    path.Data = (Geometry)TypeDescriptor.GetConverter(typeof(Geometry)).ConvertFrom(pathStr);
                    rgBrush.RadiusX = 1;
                    rgBrush.RadiusY = 1;
                    rgBrush.GradientStops.Add(new GradientStop(EdgeColor, 0d));
                    rgBrush.GradientStops.Add(new GradientStop(CenterColor, 0.5d));
                    rgBrush.GradientStops.Add(new GradientStop(EdgeColor, 1d));
                    path.Fill = rgBrush;

                    mainCanvas.Children.Add(path);
                    Canvas.SetLeft(path, p1.X - halfWidth);
                    Canvas.SetTop(path, p1.Y - halfWidth);

                }
            }
        }

        private List<Point> GetPointList()
        {
            string[] points = LinePoints.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            List<Point> pointList = new List<Point>();
            foreach (string p in points)
            {
                string[] xy = p.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                if (xy.Length == 2)
                {
                    pointList.Add(new Point() { X = double.Parse(xy[0]), Y = double.Parse(xy[1]) });
                }
            }
            return pointList;
        }

    }
}
